I don't want to dive into the technical details of COM, but to understand the potential of Visual Basic in this area you need at least to understand a few key concepts.
When Microsoft launched Windows, its first operating system able to execute multiple applications at the same time, everyone could see that Microsoft needed to devise a system for those applications to exchange data and communicate with one another. The Clipboard was good for doing simple cut-and-paste operations, but it was too primitive and didn't address the most demanding requirements that Windows now posed.
The first serious attempt in the right direction was DDE (Dynamic Data Exchange), a communication protocol that let applications call each other. DDE wasn't very successful, probably because of its lack of reliability. Even though it was extended to work on LANs (Network DDE) and was therefore able to connect applications on different workstations, few Windows applications implemented it. (Visual Basic offers limited support of DDE, but I don't cover it in this book.)
The first version of OLE (Object Linking and Embedding) for Windows 3.1 appeared in 1992 and used DDE as the underlying means for interapplication communications. OLE was the first protocol that enabled users and programmers to create compound documents—that is, documents that contain data from different applications (for example, an Excel worksheet inside a Word document). Depending on the application's needs, compound documents can completely encapsulate other simpler documents (embedding) or contain simply a reference to existing documents (linking). When the user clicks on an embedded or linked document inside a compound document, Windows runs the application that's capable of dealing with that particular type of document.
OLE 2 was released in 1993, and for the first time it included the support for in-place activation, which gave a user the ability to edit compound documents without opening a different window. For example, OLE 2 lets you edit an Excel worksheet embedded in a Word document without leaving the Word environment. But you see only the Excel menus, which replace Word's menus when you're editing the embedded data. OLE 2 was an important step also because it abandoned DDE as the communication protocol and relied instead on a new component-based architecture: COM (Component Object Model).
It gradually became apparent that the COM infrastructure was even more important than linking and embedding technologies. While the ability to create compound documents is remarkable from the user's standpoint, developers found that they could build great applications just using COM. In fact, COM promotes the concept of component-based development, which lets you subdivide large applications into smaller pieces that you can maintain and deploy more easily than you can a monolithic application. The portion of OLE that lets programs talk to each other is known as OLE Automation. Many programming languages can work as OLE Automation clients, which control other applications known as OLE Automation servers. For example, you can drive Excel and Word from the outside using Visual Basic 3 and later versions as well as VBScript.
The potential for this new programming paradigm became evident when Microsoft shipped Visual Basic 4 Enterprise Edition, which included the support for Remote Automation. Not only were Visual Basic programmers finally able to create COM components, they were also the pioneers who could launch and execute a component located on a computer across the network, using that machine's CPU, memory, and other resources. Distributed computing had made its debut on Windows platforms.
At the time Visual Basic 4 was released, another type of component appeared for the first time: OLE controls. These were the successors to the VBX controls, which had greatly contributed to the popularity of Visual Basic. The problem with VBX controls was that they were based on a proprietary architecture, namely, the Visual Basic environment, which made it nearly impossible to use them with different languages. When switching to 32-bit platforms, Microsoft decided to create a new type of controls based on OLE that could be adopted and supported by other manufacturers as well.
Remote Automation was just the test drive for the next technology, Distributed COM, or DCOM for short. DCOM was officially released with Microsoft Windows NT 4 in 1996. Many programmers continued to use Remote Automation for a while, until in 1997 Microsoft released DCOM95.EXE, which added support for DCOM even on Windows 95 systems. DCOM proved to be more efficient and reliable than Remote Automation, which Microsoft no longer revises. The only advantage of Remote Automation is its ability to communicate with 16-bit platforms. On the other hand, if you're writing Visual Basic 5 and 6 applications you're inherently addressing only 32-bit platforms, and you won't have much use for Remote Automation.
The latest technology released from Microsoft's labs is ActiveX. In a sense, ActiveX is Microsoft's answer to the new challenges of the Internet. For example, OLE controls were too heavy to be easily transferred through the Net, so Microsoft needed to devise a new type of control. Nowadays, ActiveX has become a sort of synonym for OLE, and you can refer to COM components as ActiveX components. With the advent of ActiveX, OLE Automation has been renamed simply Automation. ActiveX also introduced new words to the ever-growing developers' dictionary: ActiveX controls and ActiveX documents. ActiveX controls have replaced OLE controls, while ActiveX documents have replaced OLE documents and permit programmers to create active documents that can be opened inside a container (for example, Microsoft Internet Explorer). Visual Basic 5 and 6 can create both ActiveX controls and documents.
You can classify COM code components into three types, according to where the component runs.
The simplest type of COM component is a DLL that executes in the same address space as the application that's using it. Because each process under 32-bit platforms has its own address space, each one works with a distinct instance of the component. These components communicate directly with their clients, without the aid of COM, which makes them the most appropriate choice when speed really matters. Their main disadvantage is that the client isn't protected from the server's malfunctioning, and vice versa: If the component comes to a fatal error, its client application also crashes.
ActiveX controls are a special category of in-process components that can be hosted by an ActiveX container, such as a Visual Basic form. To qualify as an ActiveX control, a component must implement a number of interfaces defined by the ActiveX specifications. As a Visual Basic programmer, however, you don't have to worry about these additional interfaces because Visual Basic does everything for you. ActiveX controls are described in Chapter 17.
You can also compile an ActiveX component as an EXE program. This is convenient when you want to create an application that can work as a stand-alone program and offer programmable objects to the outside at the same time. The best examples of such servers are the applications in the Microsoft Office suite: You can use Excel or Word either as independent applications or as providers of components that you can use from within your own programs. EXE servers execute in their own address spaces, which makes the communication with their clients slower than with in-process components. On the other hand, ActiveX EXE servers are somewhat safer than in-process servers. If a component crashes, the client application is usually able to recover.
Remote servers are EXE programs that run on a machine different from the one that is running the client application. The client and the server communicate through DCOM (or Remote Automation). Needless to say, the communication is even slower than with local servers, but remote components offer the ability to create true distributed applications. A server executing on a remote machine doesn't take processor time or memory away from the client application, so you can subdivide complex tasks among all the machines in your network. Moreover, if you have to complete a task that heavily uses a resource located elsewhere in the network (for example, a complex query on a database engine or a lengthy print job), it's more convenient to delegate the task to a remote component that executes on the machine where the resource is physically located.
A great thing about remote servers is that they aren't different at all from regular local EXE servers. In fact, the same server can provide its services to applications on the machine where it resides (thus working as a local server) and to applications that run on other machines (thus working as a remote server).
You can also run a DLL as a remote server. To allow a DLL to live an independent life, you need to be sure that the DLL is hosted in a DLL surrogate process on the remote machine. This is the principle upon which components for Microsoft Transaction Server are based. I don't cover MTS programming in this book, though.
To let you taste the power of component-based programming, I'll show you how simple it is to add a spell checker to your Visual Basic application. Developing a spell checker program isn't a trivial task, and it could take you several months to do it, if not years. Fortunately, Microsoft Word already includes a good spell checker and, most important, Word exposes it as a programmable object through Automation. All you have to do is take advantage of this capability and create an application that uses Word as a server.
The first step for using any Automation component is to add a reference to the library in the References dialog box, which you can reach from the Project menu. Browse the list of available references, and tick "Microsoft Word 8.0 Object Library". (This example assumes that you have installed Microsoft Word 97 on your system.) After you do this, you can explore all the objects exposed by the Word library using the Object Browser, and you can even ask for help with or information about a specific method or property if you installed the VBAWRD8.hlp file. (See Figure 16-1.)
Figure 16-1. The References dialog box with the Microsoft Word library selected and the Object Browser that displays the contents of the library itself.
You can get your project to work as an Automation client even if you don't add a reference to the library. In that case, however, you must create objects using the CreateObject function instead of the New keyword. And you must store object references in generic As Object variables rather than in specific variables, which means that you can use only the less efficient late binding instead of early binding. All clients written in Visual Basic 3 and VBScript can access Automation servers only through this method.
After you've added a reference to the Word library, you can proceed as if its objects were local to your application. For example, you can declare a variable and create a new instance of the Word.Application object when your main form loads:
Dim MSWord As Word.Application Private Sub Form_Load() ' Create the instance of Word that will be used later. Set MSWord = New Word.Application End Sub |
When an object of the Word library is created, the Word application itself is invisible. This lets you use its objects without your users even noticing that you use any external library. Of course, you can make Word visible, if you want to:
MSWord.Visible = True |
The demonstration program I've prepared, however, uses Microsoft Word but hides it from users. Figure 16-2 shows what users actually see. Its main routine is the one that actually performs the spell checking and, if a word is found to be incorrect, fills the ListBox control with a list of suggestions to replace it:
Private Sub cmdCheck_Click() Dim text As String Dim suggestion As Word.SpellingSuggestion Dim colSuggestions As Word.SpellingSuggestions ' Add a document if there aren't any (needed to get suggestions). If MSWord.Documents.Count = 0 Then MSWord.Documents.Add text = Trim$(txtWord.text) lstSuggestions.Clear If MSWord.CheckSpelling(text) Then ' The word is correct. lstSuggestions.AddItem "(correct)" Else ' The word is incorrect. Get the list of suggested words. Set colSuggestions = MSWord.GetSpellingSuggestions(text) If colSuggestions.Count = 0 Then lstSuggestions.AddItem "(no suggestions)" Else For Each suggestion In colSuggestions lstSuggestions.AddItem suggestion.Name Next End If End If End Sub |
Figure 16-2. The sample application that uses Microsoft Word to check the spelling of individual words.
The key method in the cmdCheck_Click routine is CheckSpelling, which returns True if the word passed as an argument is correct and False otherwise. In the latter case, the program calls the GetSpellingSuggestions method, which returns a collection that contains 0 or more SpellingSuggestion objects. If there are any suggestions, they're enumerated using a For Each loop and loaded in the ListBox control.
The preceding routine creates an instance of the Word.Application class using the New keyword, exactly as if the class were internal to the current project. But when you're working with COM objects, you can also use the CreateObject function, which accepts the name of the class:
' An alternative way to create a Word.Application object Set MSWord = CreateObject("Word.Application") |
The CreateObject function is inherently more versatile than the New keyword because you can create the class name string at run time instead of hard coding it in the client's source code. Other subtle differences between these two ways of creating COM objects are covered in this chapter.
As you see, using external Automation objects is almost trivial, provided that you know how to exploit the methods, properties, and events exposed by the component. Besides, this simple example demonstrates the language-neutral nature of COM. Your Visual Basic program can use COM to access components written in any other language, and the opposite is also true: You can write components in Visual Basic and then use them from other development environments.
CAUTION
When declaring and creating an object that belongs to an external library, you can use the full Servername.Classname syntax instead of the plain Classname. This might be necessary to resolve any ambiguities—for example, when the application is referencing multiple external components, and two or more of them expose objects with the same name. Having two external components that expose objects with the same name is more frequent than you might expect, and if you don't take precautions you might have to face some subtle bugs. For example, both the Excel library and the Word library expose the Application object. Now, consider what happens when Visual Basic executes these statements:
Dim x As New Application x.Visible = TrueWhat window will appear, Excel's or Word's? The answer is: It depends on which library is listed first in the References dialog box. It's for this reason that this dialog box includes two Priority buttons, which let you modify the position of an item in the list. Be aware, however, that this flexibility can cause some subtle errors. For example, if you copy this code in another project that has a different list of referenced libraries, the code won't work as expected anymore. For this reason, I suggest that you always specify the full name of an external object, unless you're 100 percent sure that your application doesn't use other libraries that expose objects with the same name.